#! /bin/sh

ERL_CRASH_DUMP=${ERL_CRASH_DUMP-/dev/null}
export ERL_CRASH_DUMP

cleanup () {
  erl -pa ../src -sname fragmentron_add_node_killah -eval '
    "fragmentron_add_node_killah@" ++ Host = atom_to_list (node ()),
    Other = list_to_atom ("fragmentron_add_node_test1@" ++ Host),
    MoreOther = list_to_atom ("fragmentron_add_node_test2@" ++ Host),

    rpc:call (Other, erlang, halt, []),
    rpc:call (MoreOther, erlang, halt, [])
  ' -noshell -noinput -s erlang halt 
  wait
}

if test @HAVE_TCERL@ = yes && test @HAVE_MNESIA_EXT@ = yes
  then
    use_tcerl=true
  else
    use_tcerl=false
  fi

rm -rf Mnesia*

erl -pa ../src -sname fragmentron_add_node_test1 -s mnesia \
    -eval '
  case init:get_plain_arguments () of [ "true" ] -> tcerl:start ();
                                      [ "false" ] -> ok
  end,
  mnesia:change_table_copy_type (schema, node (), disc_copies),
  timer:sleep (30000)'  \
  -s erlang halt -noshell -noinput -extra "$use_tcerl" &

sleep 1

erl -pa ../src -sname fragmentron_add_node_test2 -s mnesia \
    -eval '
  case init:get_plain_arguments () of [ "true" ] -> tcerl:start ();
                                      [ "false" ] -> ok
  end,
  "fragmentron_add_node_test2@" ++ Host = atom_to_list (node ()),
  Self = node (),
  Other = list_to_atom ("fragmentron_add_node_test1@" ++ Host),
  mnesia:change_config (extra_db_nodes, [ Other ]),
  mnesia:change_table_copy_type (schema, node (), disc_copies),
  timer:sleep (30000)'  \
  -s erlang halt -noshell -noinput -extra "$use_tcerl" &

sleep 1

erl -pa ../src -sname fragmentron_add_node_test3 -s mnesia -eval '
  case init:get_plain_arguments () of [ "true" ] -> tcerl:start ();
                                      [ "false" ] -> ok
  end,
  "fragmentron_add_node_test3@" ++ Host = atom_to_list (node ()),
  Self = node (),
  Other = list_to_atom ("fragmentron_add_node_test1@" ++ Host),
  MoreOther = list_to_atom ("fragmentron_add_node_test2@" ++ Host),
  pong = net_adm:ping (Other),
  pong = net_adm:ping (MoreOther),
  { ok, Nodes } = mnesia:change_config (extra_db_nodes, [ Other, MoreOther ]),
  mnesia:change_table_copy_type (schema, node (), disc_copies),
  timer:sleep (1000),

  { atomic, ok } = 
    case init:get_plain_arguments () of
      [ "true" ] ->
        fragmentron:create_table (dild,
                                  [ { type, { external,
                                              ordered_set,
                                              tcbdbtab } },
                                    { frag_properties, 
                                      [ { node_pool, [ node () ] }, 
                                        { n_fragments, 1 }, 
                                        { n_external_copies, 7 } ] } ]);
      [ "false" ] ->
        fragmentron:create_table (dild,
                                  [ { frag_properties, 
                                      [ { node_pool, [ node () ] }, 
                                        { n_fragments, 1 }, 
                                        { n_disc_copies, 7 } ] } ])
    end,

  { atomic, ok } = 
    case init:get_plain_arguments () of
      [ "true" ] ->
        fragmentron:create_table (warez,
                                  [ { type, { external,
                                              ordered_set,
                                              tcbdbtab } },
                                    { frag_properties, 
                                      [ { node_pool, [ node () ] }, 
                                        { n_fragments, 3 }, 
                                        { n_external_copies, 1 } ] } ]);
      [ "false" ] ->
        fragmentron:create_table (warez,
                                  [ { frag_properties, 
                                      [ { node_pool, [ node () ] }, 
                                        { n_fragments, 3 }, 
                                        { n_disc_copies, 1 } ] } ])
    end,

  { aborted, bad_copy_spec } = 
    fragmentron:create_table (flass,
                              [ { frag_properties,
                                  [ { n_ram_copies, 4 },
                                    { foreign_key, { warez, key } } ] } ]),

  { atomic, ok } = 
    fragmentron:create_table (flass,
                              [ { frag_properties,
                                  [ { n_ram_copies, 1 },
                                    { foreign_key, { warez, key } } ] } ]),

  CopyType = case init:get_plain_arguments () of [ "true" ] -> external_copies;
                                                 [ "false" ] -> disc_copies
             end,

  { [ Self ], [ Self ], [ Self ] } = 
    { mnesia:table_info (warez, CopyType), 
      mnesia:table_info (warez_frag2, CopyType), 
      mnesia:table_info (warez_frag3, CopyType) },

  { [ Self ], [ Self ], [ Self ] } = 
    { mnesia:table_info (flass, ram_copies), 
      mnesia:table_info (flass_frag2, ram_copies), 
      mnesia:table_info (flass_frag3, ram_copies) },

  mnesia:subscribe (system),
  true = fragmentron:add_node (warez, Other),

  receive { mnesia_system_event, 
            { mnesia_user, { fragmentron, add_node, warez, Other } } } -> ok 
  after 0 -> exit (nomsg)
  end,

  receive { mnesia_system_event, 
            { mnesia_user, { fragmentron, add_node, flass, Other } } } -> 
    exit (badmsg)
  after 0 -> 
    ok
  end,

  WarezOther = 
    receive { mnesia_system_event, 
              { mnesia_user, { fragmentron, add_table_copy, T2, Other } } } when (T2 =:= warez) or (T2 =:= warez_frag2) or (T2 =:= warez_frag3) -> T2
    after 0 -> exit (nomsg_2)
    end,

  receive { mnesia_system_event, 
            { mnesia_user, { fragmentron, add_table_copy, R, Other } } } when (R =:= flass) or (R =:= flass_frag2) or (R =:= flass_frag3) -> 
    case { WarezOther, R } of
      { warez, flass } -> ok;
      { warez_frag2, flass_frag2 } -> ok;
      { warez_frag3, flass_flag3 } -> ok
    end
  after 0 -> exit (nomsg_3)
  end,

  WarezDelSelf = 
    receive { mnesia_system_event, 
              { mnesia_user, { fragmentron, del_table_copy, TD, Self } } } when (TD =:= warez) or (TD =:= warez_frag2) or (TD =:= warez_frag3) -> TD
    after 0 -> exit (nomsg_4)
    end,

  receive { mnesia_system_event, 
            { mnesia_user, { fragmentron, del_table_copy, RD, Self } } } when (RD =:= flass) or (RD =:= flass_frag2) or (RD =:= flass_frag3) -> 
    case { WarezDelSelf, RD } of
      { warez, flass } -> ok;
      { warez_frag2, flass_frag2 } -> ok;
      { warez_frag3, flass_flag3 } -> ok
    end
  after 0 -> exit (nomsg_5)
  end,

  case 
    lists:sort (
      erlang:tuple_to_list ({ mnesia:table_info (warez, CopyType),
                              mnesia:table_info (warez_frag2, CopyType), 
                              mnesia:table_info (warez_frag3, CopyType) })
    ) of
    [ [ Other ], [ Self ], [ Self ] ] -> ok
  end,

  case 
    lists:sort (
      erlang:tuple_to_list ({ mnesia:table_info (flass, ram_copies),
                              mnesia:table_info (flass_frag2, ram_copies), 
                              mnesia:table_info (flass_frag3, ram_copies) })
    ) of
    [ [ Other ], [ Self ], [ Self ] ] -> ok
  end,

  true = fragmentron:add_node (warez, MoreOther),

  receive { mnesia_system_event, 
            { mnesia_user, { fragmentron, add_node, warez, MoreOther } } } -> ok 
  after 0 -> exit (nomsg_4)
  end,

  receive { mnesia_system_event, 
            { mnesia_user, { fragmentron, add_node, flass, MoreOther } } } -> 
    exit (badmsg_2)
  after 0 -> 
    ok
  end,

  WarezMoreOther = 
    receive { mnesia_system_event, 
              { mnesia_user, { fragmentron, add_table_copy, T, MoreOther } } } when (T =:= warez) or (T =:= warez_frag2) or (T =:= warez_frag3) -> T
    after 0 -> exit (nomsg_5)
    end,

  receive { mnesia_system_event, 
            { mnesia_user, { fragmentron, add_table_copy, R2, MoreOther } } } when (R2 =:= flass) or (R2 =:= flass_frag2) or (R2 =:= flass_frag3) -> 
    case { WarezMoreOther, R2 } of
      { warez, flass } -> ok;
      { warez_frag2, flass_frag2 } -> ok;
      { warez_frag3, flass_flag3 } -> ok
    end
  after 0 -> exit (nomsg_6)
  end,

  WarezDelSelf2 = 
    receive { mnesia_system_event, 
              { mnesia_user, { fragmentron, del_table_copy, TD2, Self } } } when (TD2 =:= warez) or (TD2 =:= warez_frag2) or (TD2 =:= warez_frag3) -> TD2
    after 0 -> exit (nomsg_7)
    end,

  receive { mnesia_system_event, 
            { mnesia_user, { fragmentron, del_table_copy, RD2, Self } } } when (RD2 =:= flass) or (RD2 =:= flass_frag2) or (RD2 =:= flass_frag3) -> 
    case { WarezDelSelf2, RD2 } of
      { warez, flass } -> ok;
      { warez_frag2, flass_frag2 } -> ok;
      { warez_frag3, flass_flag3 } -> ok
    end
  after 0 -> exit (nomsg_8)
  end,

  case 
    lists:sort (
      erlang:tuple_to_list ({ mnesia:table_info (warez, CopyType),
                              mnesia:table_info (warez_frag2, CopyType), 
                              mnesia:table_info (warez_frag3, CopyType) })
    ) of
    [ [ Other ], [ MoreOther ], [ Self ] ] -> ok
  end,

  case 
    lists:sort (
      erlang:tuple_to_list ({ mnesia:table_info (flass, ram_copies),
                              mnesia:table_info (flass_frag2, ram_copies), 
                              mnesia:table_info (flass_frag3, ram_copies) })
    ) of
    [ [ Other ], [ MoreOther ], [ Self ] ] -> ok
  end,

  false = fragmentron:add_node (warez, MoreOther),

  receive { mnesia_system_event, 
            { mnesia_user, { fragmentron, _, warez, _ } } } -> exit (badmsg_3)
  after 0 -> ok
  end,

  receive { mnesia_system_event, 
            { mnesia_user, { fragmentron, _, flass, _ } } } -> exit (badmsg_4)
  after 0 -> ok
  end,

  mnesia:system_info (),

  rpc:call (Other, erlang, halt, []),
  rpc:call (MoreOther, erlang, halt, [])
' -noshell -noinput -s erlang halt -extra $use_tcerl 2>&1 > addnode.output || { cleanup; exit 1; }

wait

rm -rf Mnesia*

exit 0
